package com.apes.framework.plugin.soe.core.service;

import com.apes.framework.jpa.Model;
import com.apes.framework.jpa.generator.ApesGenerator;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.event.EventConst;
import com.apes.framework.plugin.event.Listener;
import com.apes.framework.plugin.filereader.xml.ApesElement;
import com.apes.framework.plugin.soe.annotations.Business;
import com.apes.framework.plugin.soe.annotations.States;
import com.apes.framework.plugin.soe.metadata.BusinessAction;
import com.apes.framework.plugin.soe.metadata.BusinessAttribute;
import com.apes.framework.plugin.soe.metadata.BusinessAttributeValue;
import com.apes.framework.plugin.soe.metadata.BusinessType;
import com.apes.framework.plugin.soe.store.database.service.BusinessActionService;
import com.apes.framework.plugin.soe.store.database.service.BusinessAttributeService;
import com.apes.framework.plugin.soe.store.database.service.BusinessTypeService;
import com.apes.framework.util.JpaUtil;
import com.apes.framework.util.ReflectUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.beans.PropertyDescriptor;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 功能：事件订阅服务
 *
 * @author xul
 * @create 2018-09-21 15:21
 */
@Service("eventSubscriberService")
@Order
public class EventSubscriberService implements CommandLineRunner {

    @Autowired
    private ExecutionService executionService;

    @Autowired
    private BusinessTypeService businessTypeService;

    @Autowired
    private BusinessActionService businessActionService;

    @Autowired
    private BusinessAttributeService businessAttributeService;


    public void insertBusinessAttribute(SimpleRequest request) {
        // com.apes.scm.used.model.UsedStore
        JpaUtil.getAllDomainType().forEach(domainTypeName -> {
            //if( request.get("domainTypeName").equals(domainTypeName) ){
                Class domainType = ReflectUtil.getClass(domainTypeName);
                onModelRead(domainType);
           //}
        });
    }

    /**
     * 监听Model遍历事件
     **/
    @Transactional(rollbackFor = Exception.class)
//    @Listener(topic = EventConst.EVENT_CHAIN_NODE_PARSER)
    public void chainNodeParser(SimpleRequest request) {
        ApesElement element = (ApesElement) request.getData();
        String business = element.getAttribute("business");
        if (StringUtils.isEmpty(business)) return;
        BusinessType businessType = businessTypeService.getBusinessTypeByCache(business);
        if (businessType == null) return;
        String bound = element.getAttribute("bound");
        if (StringUtils.isEmpty(bound)) return;
        String method = element.getAttribute("method");
        if (StringUtils.isEmpty(method)) return;
        String description = element.getAttribute("description");
        if (StringUtils.isEmpty(description)) return;
        BusinessAction businessAction = new BusinessAction();
        businessAction.setId(method);
        businessAction.setName(description);
        businessAction.setBusinessType(businessType);
        businessAction.setType(bound);
        businessActionService.saveAndCache(businessAction);
    }

    @Override
    public void run(String... args) throws Exception {
//        JpaUtil.getAllDomainType().forEach(domainTypeName -> {
//            Class domainType = ReflectUtil.getClass(domainTypeName);
//            onModelRead(domainType);
//        });
    }

    /**
     * 监听Model遍历事件
     **/
    @Transactional(rollbackFor = Exception.class)
    public void onModelRead(Class entityClazz) {

        /**是否聚合根**/
        boolean isAggregateRoot = Model.class.isAssignableFrom(entityClazz);

        /**存在Business注解**/
        Business business = ReflectUtil.getAnnotation(entityClazz, Business.class);
        if (business != null) {
            businessTypeService.saveAndCache(entityClazz.getSimpleName(), business.value(), isAggregateRoot);
        }

        List<PropertyDescriptor> descriptors = Arrays.asList(ReflectUtil.getPropertyDescriptors(entityClazz));
        descriptors.stream().filter(descriptor -> ReflectUtil.getAnnotation(entityClazz, descriptor.getName(), ApesGenerator.class) != null
                || ReflectUtil.getAnnotation(entityClazz, descriptor.getName(), States.class) != null).forEach(descriptor -> {
            ApesGenerator generator = ReflectUtil.getAnnotation(entityClazz, descriptor.getName(), ApesGenerator.class);
            if (business == null && generator != null) {
                businessTypeService.saveAndCache(entityClazz.getSimpleName(), generator.name(), isAggregateRoot);
            }
            States states = ReflectUtil.getAnnotation(entityClazz, descriptor.getName(), States.class);
            BusinessType businessType = businessTypeService.getBusinessTypeByCache(entityClazz.getSimpleName());
            if (states != null && businessType != null) {
                BusinessAttribute businessAttribute = new BusinessAttribute();
                businessAttribute.setBusinessType(businessType);
                businessAttribute.setCode(descriptor.getName());
                businessAttribute.setId();
                businessAttribute.setName(states.name());
                Set<BusinessAttributeValue> businessAttributeValues = new HashSet<>();
                Arrays.stream(states.values()).forEach(state -> {
                    BusinessAttributeValue businessAttributeValue = new BusinessAttributeValue();
                    businessAttributeValue.setBusinessAttribute(businessAttribute);
                    businessAttributeValue.setCode(state.id());
                    businessAttributeValue.setId();
                    businessAttributeValue.setName(state.name());
                    businessAttributeValues.add(businessAttributeValue);
                });
                businessAttribute.setBusinessAttributeValues(businessAttributeValues);
                businessAttributeService.saveBusinessAttribute(businessAttribute);
            }
        });
    }
}
